package com.firefly.admin.config.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.firefly.admin.common.constant.Constants;
import com.firefly.admin.common.enums.ResultCodeEnum;
import com.firefly.admin.common.utils.TreeUtil;
import com.firefly.admin.common.vo.Result;
import com.firefly.admin.system.entity.FySystemRoleMenu;
import com.firefly.admin.system.service.FySystemMenuService;
import com.firefly.admin.system.service.FySystemRoleMenuService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import com.firefly.admin.system.entity.FySystemMenu;
import com.firefly.admin.system.mapper.FySystemMenuMapper;
import com.firefly.admin.system.vo.MenuTree;
import com.firefly.admin.system.vo.SystemMenuQueryVo;
import com.firefly.admin.system.vo.SystemMenuStatusUpdateVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class FySystemMenuServiceImpl implements FySystemMenuService {
    @Autowired
    private FySystemMenuMapper fySystemMenuMapper;

    @Autowired
    private FySystemRoleMenuService fySystemRoleMenuService;

    /**
     * 根据角色ID列表查询权限
     *
     * @param roleIds 角色ID列表
     * @return 权限列表
     */
    @Override
    public List<FySystemMenu> getMenuListByRoleIds(List<Long> roleIds) {
        return fySystemMenuMapper.getMenuListByRoleIds(roleIds);
    }

    /**
     * 分页查询系统菜单接口
     *
     * @param systemMenuQueryVo 分页查询参数
     * @return 分页列表
     */
    @Override
    public Result<List<FySystemMenu>> getSystemMenuList(SystemMenuQueryVo systemMenuQueryVo) {
        log.info("###########FySystemMenuServiceImpl getSystemMenuList param = {}", JSONObject.toJSONString(systemMenuQueryVo));
        LambdaQueryWrapper<FySystemMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(systemMenuQueryVo.getMenuName()), FySystemMenu::getMenuName, systemMenuQueryVo.getMenuName());
        queryWrapper.eq(StringUtils.isNotBlank(systemMenuQueryVo.getMenuCode()), FySystemMenu::getMenuCode, systemMenuQueryVo.getMenuCode());
        queryWrapper.eq(StringUtils.isNotBlank(systemMenuQueryVo.getMenuStatus()), FySystemMenu::getMenuStatus, systemMenuQueryVo.getMenuStatus());
        queryWrapper.eq(StringUtils.isNotBlank(systemMenuQueryVo.getMenuType()), FySystemMenu::getMenuType, systemMenuQueryVo.getMenuType());
        queryWrapper.eq(FySystemMenu::getDeleteFlag, Constants.DeleteFlag.NORMAL);
        queryWrapper.orderByAsc(FySystemMenu::getSort);
        queryWrapper.orderByDesc(FySystemMenu::getMenuId);
        List<FySystemMenu> systemMenuList = fySystemMenuMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(systemMenuList)) {
            return Result.success();
        }
        LambdaQueryWrapper<FySystemMenu> allQueryWrapper = new LambdaQueryWrapper<>();
        allQueryWrapper.eq(FySystemMenu::getDeleteFlag, Constants.DeleteFlag.NORMAL);
        List<FySystemMenu> allMenuList = fySystemMenuMapper.selectList(allQueryWrapper);
        Map<Long, FySystemMenu> allMenuMap = allMenuList.stream().collect(Collectors.toMap(FySystemMenu::getMenuId, menu -> menu));
        List<FySystemMenu> resultMenuList = new ArrayList<>(systemMenuList);
        for (FySystemMenu fySystemMenu : systemMenuList) {
            recursionParentMenu(allMenuMap, resultMenuList, fySystemMenu);
        }
        List<FySystemMenu> menuList = TreeUtil.makeMenuList(resultMenuList, Constants.MENU_TOP_NODE);
        long endTime = System.currentTimeMillis();
        return Result.success(menuList);
    }

    private void recursionParentMenu(Map<Long, FySystemMenu> allMenuMap, List<FySystemMenu> resultMenuList, FySystemMenu fySystemMenu) {
        FySystemMenu systemMenu = allMenuMap.get(fySystemMenu.getParentId());
        fySystemMenu.setParent(systemMenu);
        if (fySystemMenu.getParentId().longValue() == Constants.MENU_TOP_NODE) {
            return;
        }
        if (systemMenu != null) {
            List<Long> collect = resultMenuList.stream().map(FySystemMenu::getMenuId).collect(Collectors.toList());
            if (!collect.contains(systemMenu.getMenuId())) {
                resultMenuList.add(systemMenu);
                recursionParentMenu(allMenuMap, resultMenuList, systemMenu);
            }
        }
    }

    /**
     * 获取系统菜单信息接口
     *
     * @param menuId 菜单ID
     * @return 菜单信息
     */
    @Override
    public Result<FySystemMenu> getSystemMenu(Long menuId) {
        if (menuId == null) {
            return Result.getResult(ResultCodeEnum.REQUEST_PARAM_EXCEPTION);
        }
        FySystemMenu fySystemMenu = fySystemMenuMapper.selectById(menuId);
        if (fySystemMenu == null) {
            return Result.getResult(ResultCodeEnum.SYSTEM_MENU_NOT_FOUND);
        }
        return Result.success(fySystemMenu);
    }

    /**
     * 系统菜单信息新增接口
     *
     * @param fySystemMenu 角色信息
     * @return 操作结果
     */
    @Override
    public Result<FySystemMenu> add(FySystemMenu fySystemMenu) {
        if (fySystemMenu == null) {
            return Result.getResult(ResultCodeEnum.REQUEST_PARAM_EXCEPTION);
        }
        ResultCodeEnum resultCodeEnum = checkMenuParam(fySystemMenu);
        if (resultCodeEnum != null) {
            return Result.getResult(resultCodeEnum);
        }
        int rows = fySystemMenuMapper.insert(fySystemMenu);
        if (rows <= 0) {
            return Result.getResult(ResultCodeEnum.ADD_EXCEPTION);
        }
        return Result.success(fySystemMenu);
    }

    /**
     * 系统菜单信息编辑接口
     *
     * @param fySystemMenu 菜单信息
     * @return 操作结果
     */
    @Override
    public Result<FySystemMenu> update(FySystemMenu fySystemMenu) {
        if (fySystemMenu == null) {
            return Result.getResult(ResultCodeEnum.REQUEST_PARAM_EXCEPTION);
        }
        Long menuId = fySystemMenu.getMenuId();
        if (menuId == null) {
            return Result.getResult(ResultCodeEnum.REQUEST_PARAM_EXCEPTION);
        }
        FySystemMenu systemMenu = fySystemMenuMapper.selectById(menuId);
        if (systemMenu == null) {
            return Result.getResult(ResultCodeEnum.SYSTEM_MENU_NOT_FOUND);
        }
        ResultCodeEnum resultCodeEnum = checkMenuParam(fySystemMenu);
        if (resultCodeEnum != null) {
            return Result.getResult(resultCodeEnum);
        }
        int rows = fySystemMenuMapper.updateById(fySystemMenu);
        if (rows <= 0) {
            return Result.getResult(ResultCodeEnum.UPDATE_EXCEPTION);
        }
        return Result.success(fySystemMenu);
    }

    /**
     * 系统菜单状态编辑接口
     *
     * @param systemMenuStatusUpdateVo 状态信息
     * @return 操作结果
     */
    @Override
    public Result<FySystemMenu> updateStatus(SystemMenuStatusUpdateVo systemMenuStatusUpdateVo) {
        if (systemMenuStatusUpdateVo == null) {
            return Result.getResult(ResultCodeEnum.REQUEST_PARAM_EXCEPTION);
        }
        Long menuId = systemMenuStatusUpdateVo.getMenuId();
        if (menuId == null) {
            return Result.getResult(ResultCodeEnum.REQUEST_PARAM_EXCEPTION);
        }
        FySystemMenu fySystemMenu = fySystemMenuMapper.selectById(menuId);
        if (fySystemMenu == null) {
            return Result.getResult(ResultCodeEnum.SYSTEM_MENU_NOT_FOUND);
        }
        String menuStatus = systemMenuStatusUpdateVo.getMenuStatus();
        if (StringUtils.isBlank(menuStatus)) {
            return Result.getResult(ResultCodeEnum.SYSTEM_MENU_STATUS_NOT_NULL);
        }
        //停用删除角色和菜单关联信息
        if (Constants.Status.DISABLE.equals(menuStatus)) {
            fySystemRoleMenuService.deleteByMenuId(menuId);
        }
        fySystemMenu.setMenuStatus(menuStatus);
        int rows = fySystemMenuMapper.updateById(fySystemMenu);
        if (rows <= 0) {
            return Result.getResult(ResultCodeEnum.UPDATE_EXCEPTION);
        }
        return Result.success(fySystemMenu);
    }

    /**
     * 根据角色ID列表获取菜单列表接口
     *
     * @return 菜单树
     */
    @Override
    public Result<List<MenuTree>> getMenuTreeByRoleIds(String roleIds) {
        List<MenuTree> menuTreeList = new ArrayList<>();
        if (StringUtils.isNotBlank(roleIds)) {
            List<Long> ids = new ArrayList<>();
            Arrays.asList(roleIds.split(StringPool.COMMA)).forEach(id -> ids.add(Long.valueOf(id)));
            List<FySystemMenu> systemMenuList = fySystemMenuMapper.getMenuListByRoleIds(ids);
            menuTreeList = TreeUtil.makeMenuTree(systemMenuList, Constants.MENU_TOP_NODE);
        }
        return Result.success(menuTreeList);
    }

    /**
     * 获取可用菜单树列表接口
     *
     * @return 菜单树列表
     */
    @Override
    public Result<List<MenuTree>> getAllUsableMenuTree() {
        LambdaQueryWrapper<FySystemMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FySystemMenu::getMenuStatus, Constants.Status.ENABLE);
        queryWrapper.eq(FySystemMenu::getDeleteFlag, Constants.DeleteFlag.NORMAL);
        List<FySystemMenu> systemMenuList = fySystemMenuMapper.selectList(queryWrapper);
        List<MenuTree> menuTreeList = TreeUtil.makeMenuTree(systemMenuList, Constants.MENU_TOP_NODE);
        return Result.success(menuTreeList);
    }

    /**
     * 获取菜单树列表接口
     *
     * @return 菜单树列表
     */
    @Override
    public Result<List<MenuTree>> getMenuTree() {
        LambdaQueryWrapper<FySystemMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FySystemMenu::getMenuStatus, Constants.Status.ENABLE);
        queryWrapper.eq(FySystemMenu::getMenuType, Constants.PERMISSION_TYPE_MENU);
        queryWrapper.eq(FySystemMenu::getDeleteFlag, Constants.DeleteFlag.NORMAL);
        List<FySystemMenu> systemMenuList = fySystemMenuMapper.selectList(queryWrapper);
        List<MenuTree> menuTreeList = new ArrayList<>();
        FySystemMenu fySystemMenu = fySystemMenuMapper.selectById(Constants.MENU_TOP_NODE);
        MenuTree menuTree = new MenuTree();
        menuTree.setMenuId(fySystemMenu.getMenuId());
        menuTree.setLabel(fySystemMenu.getMenuName());
        List<MenuTree> children = TreeUtil.makeMenuTree(systemMenuList, Constants.MENU_TOP_NODE);
        menuTree.setChildren(children);
        menuTreeList.add(menuTree);
        return Result.success(menuTreeList);
    }

    /**
     * 系统菜单信息删除接口
     *
     * @param menuId 菜单ID
     * @return 操作结果
     */
    @Override
    @Transactional
    public Result<String> delete(Long menuId) {
        if (menuId == null) {
            return Result.getResult(ResultCodeEnum.REQUEST_PARAM_EXCEPTION);
        }
        FySystemMenu fySystemMenu = fySystemMenuMapper.selectById(menuId);
        if (fySystemMenu == null) {
            return Result.getResult(ResultCodeEnum.SYSTEM_ROLE_NOT_FOUND);
        }
        Set<Long> allChildrenIds = getAllChildrenIds(menuId);
        allChildrenIds.add(menuId);
        fySystemRoleMenuService.deleteByMenuIds(allChildrenIds);
        LambdaQueryWrapper<FySystemMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(FySystemMenu::getMenuId, allChildrenIds);
        FySystemMenu systemMenu = new FySystemMenu();
        systemMenu.setDeleteFlag(Constants.DeleteFlag.DELETE);
        int rows = fySystemMenuMapper.update(systemMenu, queryWrapper);
        if (rows <= 0) {
            return Result.getResult(ResultCodeEnum.DELETE_EXCEPTION);
        }
        return Result.success();
    }

    /**
     * 校验用户是否有当前菜单权限
     *
     * @param menuId 菜单ID
     * @param userId 用户ID
     * @return 是否有权限
     */
    @Override
    public boolean checkUserMenu(Long menuId, Long userId) {
        int count = fySystemMenuMapper.selectByUserIdAndMenuId(userId, menuId);
        return count != 0;
    }

    private Set<Long> getAllChildrenIds(Long menuId) {
        Set<Long> childrenIds = new HashSet<>();
        LambdaQueryWrapper<FySystemMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FySystemMenu::getParentId, menuId);
        queryWrapper.eq(FySystemMenu::getDeleteFlag, Constants.DeleteFlag.NORMAL);
        List<FySystemMenu> systemMenuList = fySystemMenuMapper.selectList(queryWrapper);
        if (!CollectionUtils.isEmpty(systemMenuList)) {
            for (FySystemMenu fySystemMenu : systemMenuList) {
                childrenIds.add(fySystemMenu.getMenuId());
                Set<Long> allChildrenIdList = getAllChildrenIds(fySystemMenu.getMenuId());
                childrenIds.addAll(allChildrenIdList);
            }
        }
        return childrenIds;
    }

    /**
     * 获取可用菜单列表接口
     *
     * @return 菜单列表
     */
    @Override
    public Result<List<FySystemMenu>> getAllUsableMenuList() {
        LambdaQueryWrapper<FySystemMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FySystemMenu::getMenuStatus, Constants.Status.ENABLE);
        queryWrapper.eq(FySystemMenu::getMenuType, Constants.PERMISSION_TYPE_MENU);
        queryWrapper.eq(FySystemMenu::getDeleteFlag, Constants.DeleteFlag.NORMAL);
        List<FySystemMenu> systemMenuList = fySystemMenuMapper.selectList(queryWrapper);
        return Result.success(systemMenuList);
    }

    /**
     * 系统菜单编码校验接口
     *
     * @param menuCode 菜单编码
     * @param menuId   菜单ID
     * @return 校验结果
     */
    @Override
    public Result<String> menuCodeCheck(String menuCode, Long menuId) {
        if (StringUtils.isBlank(menuCode)) {
            return Result.getResult(ResultCodeEnum.SYSTEM_MENU_CODE_NOT_NULL);
        }
        LambdaQueryWrapper<FySystemMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FySystemMenu::getMenuCode, menuCode);
        queryWrapper.eq(FySystemMenu::getDeleteFlag, Constants.DeleteFlag.NORMAL);
        List<FySystemMenu> systemMenuList = fySystemMenuMapper.selectList(queryWrapper);
        if (!CollectionUtils.isEmpty(systemMenuList)) {
            if (menuId == null) {
                //新增
                return Result.success(ResultCodeEnum.SYSTEM_MENU_CODE_EXIST.getMsg());
            } else {
                //编辑
                for (FySystemMenu systemMenu : systemMenuList) {
                    if (menuId.longValue() != systemMenu.getMenuId().longValue()) {
                        return Result.success(ResultCodeEnum.SYSTEM_MENU_CODE_EXIST.getMsg());
                    }
                }
            }
        }
        return Result.success();
    }

    /**
     * 新增编辑参数校验
     *
     * @param fySystemMenu 菜单信息
     * @return 结果
     */
    private ResultCodeEnum checkMenuParam(FySystemMenu fySystemMenu) {
        Long parentId = fySystemMenu.getParentId();
        if (parentId == null) {
            return ResultCodeEnum.SYSTEM_MENU_PARENT_NOT_NULL;
        }
        FySystemMenu parentMenu = fySystemMenuMapper.selectById(parentId);
        if (parentMenu == null) {
            return ResultCodeEnum.SYSTEM_MENU_PARENT_NOT_FOUND;
        }
        String menuCode = fySystemMenu.getMenuCode();
        if (StringUtils.isBlank(menuCode)) {
            return ResultCodeEnum.SYSTEM_MENU_CODE_NOT_NULL;
        }
        LambdaQueryWrapper<FySystemMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FySystemMenu::getMenuCode, menuCode);
        queryWrapper.eq(FySystemMenu::getDeleteFlag, Constants.DeleteFlag.NORMAL);
        List<FySystemMenu> fySystemMenus = fySystemMenuMapper.selectList(queryWrapper);
        Long menuId = fySystemMenu.getMenuId();
        if (!CollectionUtils.isEmpty(fySystemMenus)) {
            if (menuId == null) {
                //新增
                return ResultCodeEnum.SYSTEM_MENU_CODE_EXIST;
            } else {
                //编辑
                for (FySystemMenu systemMenu : fySystemMenus) {
                    if (menuId.longValue() != systemMenu.getMenuId().longValue()) {
                        return ResultCodeEnum.SYSTEM_MENU_CODE_EXIST;
                    }
                }
            }
        }
        String menuName = fySystemMenu.getMenuName();
        if (StringUtils.isBlank(menuName)) {
            return ResultCodeEnum.SYSTEM_MENU_NAME_NOT_NULL;
        }
        String menuStatus = fySystemMenu.getMenuStatus();
        if (menuId == null && StringUtils.isBlank(menuStatus)) {
            fySystemMenu.setMenuStatus(Constants.Status.ENABLE);
        }
        String menuType = fySystemMenu.getMenuType();
        if (StringUtils.isBlank(menuType)) {
            return ResultCodeEnum.SYSTEM_MENU_TYPE_NOT_NULL;
        }
        String menuPath = fySystemMenu.getMenuPath();
        if (StringUtils.isBlank(menuPath)) {
            return ResultCodeEnum.SYSTEM_MENU_TYPE_NOT_NULL;
        }
        return null;
    }
}
